From 578c1a11696b56cfe8321cb86d784bf2105104a2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 28 Aug 2016 15:10:27 +0300 Subject: [PATCH] `cargo metadata` works with workspaces --- src/cargo/ops/cargo_output_metadata.rs | 25 +++-- src/cargo/ops/resolve.rs | 19 ++-- tests/metadata.rs | 127 ++++++++++++++++++++++++- 3 files changed, 150 insertions(+), 21 deletions(-) diff --git a/src/cargo/ops/cargo_output_metadata.rs b/src/cargo/ops/cargo_output_metadata.rs index 658a588af..5178dbc8e 100644 --- a/src/cargo/ops/cargo_output_metadata.rs +++ b/src/cargo/ops/cargo_output_metadata.rs @@ -33,7 +33,8 @@ pub fn output_metadata(ws: &Workspace, fn metadata_no_deps(ws: &Workspace, _opt: &OutputMetadataOptions) -> CargoResult { Ok(ExportInfo { - packages: vec![try!(ws.current()).clone()], + packages: ws.members().cloned().collect(), + workspace_members: ws.members().map(|pkg| pkg.package_id().clone()).collect(), resolve: None, version: VERSION, }) @@ -53,7 +54,11 @@ fn metadata_full(ws: &Workspace, Ok(ExportInfo { packages: packages, - resolve: Some(MetadataResolve(resolve, try!(ws.current()).package_id().clone())), + workspace_members: ws.members().map(|pkg| pkg.package_id().clone()).collect(), + resolve: Some(MetadataResolve{ + resolve: resolve, + root: ws.current_opt().map(|pkg| pkg.package_id().clone()), + }), version: VERSION, }) } @@ -61,6 +66,7 @@ fn metadata_full(ws: &Workspace, #[derive(RustcEncodable)] pub struct ExportInfo { packages: Vec, + workspace_members: Vec, resolve: Option, version: u32, } @@ -68,13 +74,16 @@ pub struct ExportInfo { /// Newtype wrapper to provide a custom `Encodable` implementation. /// The one from lockfile does not fit because it uses a non-standard /// format for `PackageId`s -struct MetadataResolve(Resolve, PackageId); +struct MetadataResolve{ + resolve: Resolve, + root: Option, +} impl Encodable for MetadataResolve { fn encode(&self, s: &mut S) -> Result<(), S::Error> { #[derive(RustcEncodable)] struct EncodableResolve<'a> { - root: &'a PackageId, + root: Option<&'a PackageId>, nodes: Vec>, } @@ -84,14 +93,12 @@ impl Encodable for MetadataResolve { dependencies: Vec<&'a PackageId>, } - let resolve = &self.0; - let root = &self.1; let encodable = EncodableResolve { - root: root, - nodes: resolve.iter().map(|id| { + root: self.root.as_ref(), + nodes: self.resolve.iter().map(|id| { Node { id: id, - dependencies: resolve.deps(id).collect(), + dependencies: self.resolve.deps(id).collect(), } }).collect(), }; diff --git a/src/cargo/ops/resolve.rs b/src/cargo/ops/resolve.rs index eb5713294..7ab3d1b4c 100644 --- a/src/cargo/ops/resolve.rs +++ b/src/cargo/ops/resolve.rs @@ -60,21 +60,18 @@ pub fn resolve_with_previous<'a>(registry: &mut PackageRegistry, .clone()])); // If we're resolving everything then we include all members of the - // workspace. If we want a specific set of requirements then we only - // resolve the main crate as it's the only one we're compiling. This + // workspace. If we want a specific set of requirements and we're + // compiling only a single workspace crate then resolve only it. This // case should only happen after we have a previous resolution, however, // so assert that the previous exists. - let method = match method { - Method::Everything => Method::Everything, - Method::Required { .. } => { - assert!(previous.is_some()); - if member.package_id() == try!(ws.current()).package_id() { - method - } else { - continue + if let Method::Required { .. } = method { + assert!(previous.is_some()); + if let Some(current) = ws.current_opt() { + if member.package_id() != current.package_id() { + continue; } } - }; + } // If we don't have a previous instance of resolve then we just need to // resolve our entire summary (method should be Everything) and we just diff --git a/tests/metadata.rs b/tests/metadata.rs index 4d5df0f41..2f2c21056 100644 --- a/tests/metadata.rs +++ b/tests/metadata.rs @@ -3,7 +3,7 @@ extern crate hamcrest; use hamcrest::assert_that; use cargotest::support::registry::Package; -use cargotest::support::{project, execs, basic_bin_manifest, main_file}; +use cargotest::support::{project, execs, basic_bin_manifest, basic_lib_manifest, main_file}; #[test] fn cargo_metadata_simple() { @@ -32,6 +32,7 @@ fn cargo_metadata_simple() { "manifest_path": "[..]Cargo.toml" } ], + "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"], "resolve": { "nodes": [ { @@ -149,6 +150,7 @@ fn cargo_metadata_with_deps_and_version() { "version": "0.5.0" } ], + "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"], "resolve": { "nodes": [ { @@ -174,6 +176,128 @@ fn cargo_metadata_with_deps_and_version() { }"#)); } +#[test] +fn workspace_metadata() { + let p = project("foo") + .file("Cargo.toml", r#" + [workspace] + members = ["bar", "baz"] + "#) + .file("bar/Cargo.toml", &basic_lib_manifest("bar")) + .file("bar/src/lib.rs", "") + .file("baz/Cargo.toml", &basic_lib_manifest("baz")) + .file("baz/src/lib.rs", ""); + p.build(); + + assert_that(p.cargo_process("metadata"), execs().with_status(0).with_json(r#" + { + "packages": [ + { + "name": "bar", + "version": "0.5.0", + "id": "bar[..]", + "source": null, + "dependencies": [], + "targets": [ + { + "kind": [ "lib" ], + "name": "bar", + "src_path": "[..]bar[..]src[..]lib.rs" + } + ], + "features": {}, + "manifest_path": "[..]bar[..]Cargo.toml" + }, + { + "name": "baz", + "version": "0.5.0", + "id": "baz[..]", + "source": null, + "dependencies": [], + "targets": [ + { + "kind": [ "lib" ], + "name": "baz", + "src_path": "[..]baz[..]src[..]lib.rs" + } + ], + "features": {}, + "manifest_path": "[..]baz[..]Cargo.toml" + } + ], + "workspace_members": ["baz 0.5.0 (path+file:[..]baz)", "bar 0.5.0 (path+file:[..]bar)"], + "resolve": { + "nodes": [ + { + "dependencies": [], + "id": "baz 0.5.0 (path+file:[..]baz)" + }, + { + "dependencies": [], + "id": "bar 0.5.0 (path+file:[..]bar)" + } + ], + "root": null + }, + "version": 1 + }"#)) +} + +#[test] +fn workspace_metadata_no_deps() { + let p = project("foo") + .file("Cargo.toml", r#" + [workspace] + members = ["bar", "baz"] + "#) + .file("bar/Cargo.toml", &basic_lib_manifest("bar")) + .file("bar/src/lib.rs", "") + .file("baz/Cargo.toml", &basic_lib_manifest("baz")) + .file("baz/src/lib.rs", ""); + p.build(); + + assert_that(p.cargo_process("metadata").arg("--no-deps"), execs().with_status(0).with_json(r#" + { + "packages": [ + { + "name": "bar", + "version": "0.5.0", + "id": "bar[..]", + "source": null, + "dependencies": [], + "targets": [ + { + "kind": [ "lib" ], + "name": "bar", + "src_path": "[..]bar[..]src[..]lib.rs" + } + ], + "features": {}, + "manifest_path": "[..]bar[..]Cargo.toml" + }, + { + "name": "baz", + "version": "0.5.0", + "id": "baz[..]", + "source": null, + "dependencies": [], + "targets": [ + { + "kind": [ "lib" ], + "name": "baz", + "src_path": "[..]baz[..]src[..]lib.rs" + } + ], + "features": {}, + "manifest_path": "[..]baz[..]Cargo.toml" + } + ], + "workspace_members": ["baz 0.5.0 (path+file:[..]baz)", "bar 0.5.0 (path+file:[..]bar)"], + "resolve": null, + "version": 1 + }"#)) +} + #[test] fn cargo_metadata_with_invalid_manifest() { let p = project("foo") @@ -204,6 +328,7 @@ const MANIFEST_OUTPUT: &'static str= "features":{}, "manifest_path":"[..]Cargo.toml" }], + "workspace_members": [ "foo 0.5.0 (path+file:[..]foo)" ], "resolve": null, "version": 1 }"#; -- 2.30.2